namespace Resonator.Tests.Services
{
	using System;
	using System.Collections.Generic;
	using System.ComponentModel.Design;
	using System.IO;
	using System.Text;
	using ICSharpCode.SharpZipLib.Zip;
	using NUnit.Framework;
	using Resonator.Core.Services;
	using Resonator.Domain.Models;
	using Resonator.Domain.Services;
	using Rhino.Mocks;

	[TestFixture]
	[Category("Parser")]
	public class ZipResourceParserTester
	{
		private MockRepository _mocks;

		[SetUp]
		public void SetUp()
		{
			_mocks = new MockRepository();
			_resourceParser = new ZipResourceParser();
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Depends_On_ResourceParserProvider()
		{
			new ZipResourceParser(null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Resouce_Stream_Is_Required()
		{
			new ZipResourceParser().Parse(null);
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Default_Culture_Is_Required()
		{
			new ZipResourceParser().Parse(new ResourceStream(string.Empty, new MemoryStream()), null);
		}

		[Test]
		public void Parses_Entries_Contained_In_Zip_Archive()
		{
			string input1 = MockResx( "<data name=\"Yes\"><value>Yes</value></data>" );
			ResourceStream resourceFile1 = new ResourceStream( "Mock.Resx", StringStream( input1 ) );

			string input2 = MockResx( "<data name=\"Yes\"><value>Si</value></data>" );
			ResourceStream resourceFile2 = new ResourceStream( "Mock.es-ES.Resx", StringStream( input2 ) );

			ResourceStream zipStream = new ResourceStream( "Mock.zip", ZipStream( resourceFile1, resourceFile2 ) );

			IList<Resource> resources = _resourceParser.Parse( zipStream );

			Assert.IsNotNull( resources );
			Assert.AreEqual( 2, resources.Count );
			Assert.AreEqual( "Mock.Yes", resources[0].Name );
			Assert.AreEqual( "Yes", resources[0].Phrase );
			Assert.AreEqual( "Mock.Yes", resources[1].Name );
			Assert.AreEqual( "Si", resources[1].Phrase );
		}

		[Test]
		[ExpectedException(typeof(ResonatorException))]
		public void Throws_When_Unable_To_Determine_Parser_To_User()
		{
			string input1 = MockResx("<data name=\"Yes\"><value>Yes</value></data>");
			ResourceStream resourceFile1 = new ResourceStream("Mock.Resx", StringStream(input1));

			string input2 = MockResx("<data name=\"Yes\"><value>Si</value></data>");
			ResourceStream resourceFile2 = new ResourceStream("Mock.es-ES.Resx", StringStream(input2));

			ResourceStream zipStream = new ResourceStream("Mock.zip", ZipStream(resourceFile1, resourceFile2));

			IResourceParserProvider parserProvider = _mocks.DynamicMock<IResourceParserProvider>();
			SetupResult.For( parserProvider.Get( null ) ).IgnoreArguments().Return( null );

			_resourceParser = new ZipResourceParser( parserProvider ); 
			IList<Resource> resources = _resourceParser.Parse(zipStream);
		}

		protected static readonly string RESX_TEMPLATE =
			"<root><resheader name=\"resmimetype\"><value>text/microsoft-resx</value></resheader><resheader name=\"version\"><value>2.0</value></resheader><resheader name=\"reader\"><value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader><resheader name=\"writer\"><value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value></resheader>{0}</root>";

		private IResourceParser _resourceParser;

		protected static Stream StringStream(string text)
		{
			byte[] textBytes = Encoding.UTF8.GetBytes( text );
			return new MemoryStream( textBytes );
		}

		protected static string MockResx(string data)
		{
			return string.Format( RESX_TEMPLATE, data );
		}

		protected static Stream ZipStream(params ResourceStream[] resourceStreams)
		{
			MemoryStream stream = new MemoryStream();

			ZipOutputStream zipStream = new ZipOutputStream( stream );
			foreach( ResourceStream resourceFile in resourceStreams )
			{
				zipStream.PutNextEntry( new ZipEntry( resourceFile.Name ) );
				byte[] buffer = new byte[resourceFile.Stream.Length];
				resourceFile.Stream.Read( buffer, 0, buffer.Length );
				zipStream.Write( buffer, 0, buffer.Length );
				zipStream.CloseEntry();
			}
			zipStream.Finish();

			stream.Seek( 0, SeekOrigin.Begin );

			return stream;
		}
	}
}